Skip to content

feat(scheduler): add gpujoborder plugin for configurable JobOrderFn tiebreak - #1995

Merged
davidLif merged 14 commits into
kai-scheduler:mainfrom
CoolingCube:resourceaware-tiebreak
Aug 23, 2026
Merged

feat(scheduler): add gpujoborder plugin for configurable JobOrderFn tiebreak#1995
davidLif merged 14 commits into
kai-scheduler:mainfrom
CoolingCube:resourceaware-tiebreak

Conversation

@CoolingCube

@CoolingCube CoolingCube commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Description

Adds an additive JobOrderFn plugin that activates only when the existing
priority plugin's comparison ties (composition is additive per
session_plugins.go; no changes to priority.go or the composition
mechanism itself).

Configurable via mode argument: prefer-larger (default) or
prefer-smaller, comparing GetAliveTasksRequestedGPUs() between
same-priority jobs. Unrecognized mode values log a warning and fall back
to prefer-larger. Falls through unchanged to the existing
CreationTimestamp/UID tiebreak if GPU counts also match.

A dominant-resource mode (comparing by whichever resource represents a
job's largest relative share) was discussed in #1966 but isn't included —
ClusterInfo has no pre-computed total cluster capacity, so it would need
its own summation over Nodes mirroring what proportion.go does for
queue fair-share, rather than being a quick addition. Happy to take that
on as a follow-up if there's interest.

Related Issues

Fixes #1966

Checklist

  • Self-reviewed
  • Added/updated tests (if needed) — 5 unit tests: priority-difference
    deferral, both modes' comparison behavior, same-priority-same-GPU
    fallthrough, unrecognized-mode fallback
  • Updated documentation (if needed)
  • Added a changelog fragment via make changelog

Breaking Changes

None — purely additive; no existing plugin or behavior is modified.

Additional Notes

Full design discussion and the live reversed-creation-order test that
motivated this are in #1966.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: da845c56-de33-4f5d-8449-541163b9dfd1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@enoodle

enoodle commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

@CoolingCube Can you please use the PR template ? https://github.com/kai-scheduler/KAI-Scheduler/blob/main/.github/pull_request_template.md
It will help with review.

@CoolingCube CoolingCube changed the title Add resourceaware plugin: configurable resource-based JobOrderFn tiebreak feat(scheduler): add resourceaware plugin for configurable JobOrderFn tiebreak Jul 29, 2026
…reak

Signed-off-by: CoolingCube <CoolingCubeInfo@proton.me>
…lause

Signed-off-by: CoolingCube <CoolingCubeInfo@proton.me>
Signed-off-by: CoolingCube <CoolingCubeInfo@proton.me>
@CoolingCube
CoolingCube force-pushed the resourceaware-tiebreak branch from d6b6be8 to c5ff98c Compare July 29, 2026 13:00
Comment thread pkg/scheduler/plugins/resourceaware/resourceaware.go Outdated
Comment thread pkg/scheduler/plugins/resourceaware/resourceaware.go Outdated
…larity

Signed-off-by: CoolingCube <CoolingCubeInfo@proton.me>
@CoolingCube
CoolingCube force-pushed the resourceaware-tiebreak branch from 4170bca to 279043f Compare July 30, 2026 15:11
@CoolingCube CoolingCube changed the title feat(scheduler): add resourceaware plugin for configurable JobOrderFn tiebreak feat(scheduler): add gpujoborder plugin for configurable JobOrderFn tiebreak Jul 30, 2026
Signed-off-by: CoolingCube <CoolingCubeInfo@proton.me>
@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown

📊 Performance Benchmark Results

Comparing PR (resourceaware-tiebreak) vs main branch — click to expand
goos: linux
goarch: amd64
pkg: github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/actions
cpu: AMD EPYC 7763 64-Core Processor                
                                    │ main-bench.txt │           pr-bench.txt            │
                                    │     sec/op     │   sec/op     vs base              │
AllocateAction_SmallCluster-4            108.6m ± 0%   108.6m ± 7%       ~ (p=1.000 n=6)
AllocateAction_MediumCluster-4           136.7m ± 1%   136.0m ± 1%       ~ (p=0.065 n=6)
AllocateAction_LargeCluster-4            202.0m ± 3%   199.0m ± 2%       ~ (p=0.180 n=6)
ReclaimAction_SmallCluster-4             103.8m ± 0%   103.7m ± 0%       ~ (p=0.699 n=6)
ReclaimAction_MediumCluster-4            107.3m ± 1%   106.7m ± 0%  -0.61% (p=0.026 n=6)
PreemptAction_SmallCluster-4             104.8m ± 0%   104.6m ± 0%       ~ (p=0.132 n=6)
PreemptAction_MediumCluster-4            117.0m ± 2%   117.0m ± 2%       ~ (p=0.589 n=6)
ConsolidationAction_SmallCluster-4       123.3m ± 1%   123.2m ± 1%       ~ (p=0.485 n=6)
ConsolidationAction_MediumCluster-4      270.5m ± 1%   263.9m ± 2%  -2.42% (p=0.015 n=6)
FullSchedulingCycle_SmallCluster-4       106.4m ± 0%   106.3m ± 0%       ~ (p=0.310 n=6)
FullSchedulingCycle_MediumCluster-4      121.0m ± 0%   120.2m ± 2%       ~ (p=0.065 n=6)
FullSchedulingCycle_LargeCluster-4       156.9m ± 1%   156.0m ± 1%       ~ (p=0.394 n=6)
ManyQueues_MediumCluster-4               138.9m ± 1%   138.1m ± 1%       ~ (p=0.310 n=6)
GangScheduling_MediumCluster-4           159.6m ± 2%   157.6m ± 1%       ~ (p=0.132 n=6)
geomean                                  134.2m        133.3m       -0.61%

                                    │ main-bench.txt │            pr-bench.txt            │
                                    │      B/op      │     B/op      vs base              │
AllocateAction_SmallCluster-4           2.078Mi ± 1%   2.085Mi ± 1%       ~ (p=0.394 n=6)
AllocateAction_MediumCluster-4          9.904Mi ± 0%   9.903Mi ± 0%       ~ (p=0.310 n=6)
AllocateAction_LargeCluster-4           31.26Mi ± 0%   31.26Mi ± 0%       ~ (p=0.699 n=6)
ReclaimAction_SmallCluster-4            955.4Ki ± 0%   951.9Ki ± 1%       ~ (p=0.394 n=6)
ReclaimAction_MediumCluster-4           3.106Mi ± 0%   3.103Mi ± 0%       ~ (p=0.394 n=6)
PreemptAction_SmallCluster-4            1.346Mi ± 1%   1.347Mi ± 0%       ~ (p=0.485 n=6)
PreemptAction_MediumCluster-4           5.936Mi ± 0%   5.936Mi ± 0%       ~ (p=0.132 n=6)
ConsolidationAction_SmallCluster-4      8.211Mi ± 0%   8.204Mi ± 0%       ~ (p=0.240 n=6)
ConsolidationAction_MediumCluster-4     67.76Mi ± 0%   67.76Mi ± 0%       ~ (p=0.310 n=6)
FullSchedulingCycle_SmallCluster-4      1.408Mi ± 1%   1.408Mi ± 1%       ~ (p=0.937 n=6)
FullSchedulingCycle_MediumCluster-4     6.140Mi ± 0%   6.139Mi ± 0%       ~ (p=0.818 n=6)
FullSchedulingCycle_LargeCluster-4      18.35Mi ± 0%   18.35Mi ± 0%       ~ (p=0.589 n=6)
ManyQueues_MediumCluster-4              13.13Mi ± 0%   13.13Mi ± 0%       ~ (p=0.394 n=6)
GangScheduling_MediumCluster-4          15.33Mi ± 0%   15.33Mi ± 0%       ~ (p=0.240 n=6)
geomean                                 6.545Mi        6.544Mi       -0.01%

                                    │ main-bench.txt │           pr-bench.txt            │
                                    │   allocs/op    │  allocs/op   vs base              │
AllocateAction_SmallCluster-4            31.49k ± 0%   31.49k ± 0%       ~ (p=0.221 n=6)
AllocateAction_MediumCluster-4           245.8k ± 0%   245.8k ± 0%       ~ (p=0.732 n=6)
AllocateAction_LargeCluster-4            1.007M ± 0%   1.007M ± 0%       ~ (p=1.000 n=6)
ReclaimAction_SmallCluster-4             8.937k ± 0%   8.937k ± 0%       ~ (p=1.000 n=6)
ReclaimAction_MediumCluster-4            28.12k ± 0%   28.12k ± 0%       ~ (p=0.056 n=6)
PreemptAction_SmallCluster-4             15.27k ± 0%   15.27k ± 0%       ~ (p=0.595 n=6)
PreemptAction_MediumCluster-4            55.29k ± 0%   55.29k ± 0%       ~ (p=1.000 n=6)
ConsolidationAction_SmallCluster-4       109.7k ± 0%   109.6k ± 0%       ~ (p=0.087 n=6)
ConsolidationAction_MediumCluster-4      1.020M ± 0%   1.020M ± 0%       ~ (p=0.065 n=6)
FullSchedulingCycle_SmallCluster-4       19.63k ± 0%   19.63k ± 0%       ~ (p=1.000 n=6)
FullSchedulingCycle_MediumCluster-4      136.3k ± 0%   136.3k ± 0%       ~ (p=1.000 n=6)
FullSchedulingCycle_LargeCluster-4       537.6k ± 0%   537.6k ± 0%       ~ (p=0.331 n=6)
ManyQueues_MediumCluster-4               274.0k ± 0%   274.0k ± 0%       ~ (p=0.100 n=6)
GangScheduling_MediumCluster-4           455.3k ± 0%   455.3k ± 0%       ~ (p=0.937 n=6)
geomean                                  109.0k        109.0k       -0.00%

pkg: github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/actions/integration_tests/reclaim
                                                          │ main-bench.txt │            pr-bench.txt            │
                                                          │     sec/op     │    sec/op     vs base              │
ReclaimLargeJobs_10Node-4                                     140.1m ±  1%    138.9m ± 1%  -0.87% (p=0.009 n=6)
ReclaimLargeJobs_50Node-4                                     335.0m ±  4%    331.4m ± 6%       ~ (p=0.699 n=6)
ReclaimLargeJobs_100Node-4                                    683.0m ±  2%    660.1m ± 1%  -3.36% (p=0.002 n=6)
ReclaimLargeJobs_200Node-4                                     1.681 ±  1%     1.666 ± 1%       ~ (p=0.240 n=6)
ReclaimLargeJobs_500Node-4                                     7.729 ±  2%     7.697 ± 2%       ~ (p=0.180 n=6)
ReclaimLargeJobs_1000Node-4                                    33.65 ±  2%     33.51 ± 1%       ~ (p=0.589 n=6)
ReclaimManySingleGPUJobsFullCycle_10Node-4                    161.4m ±  0%    162.0m ± 1%       ~ (p=0.065 n=6)
ReclaimManySingleGPUJobsFullCycle_50Node-4                    998.9m ±  1%   1017.7m ± 6%  +1.88% (p=0.002 n=6)
ReclaimManySingleGPUJobsFullCycle_100Node-4                    3.502 ±  2%     3.640 ± 7%  +3.93% (p=0.004 n=6)
ReclaimManySingleGPUJobsFullCycle_200Node-4                    15.34 ± 10%     15.37 ± 5%       ~ (p=1.000 n=6)
ReclaimManySingleGPUJobsFullCycle_500Node-4                    117.7 ±  6%     123.0 ± 6%       ~ (p=0.240 n=6)
ReclaimManySingleGPUJobsFullCycleWithMinRuntime_500Node-4      115.7 ±  4%     117.3 ± 2%       ~ (p=0.240 n=6)
geomean                                                        3.298           3.311       +0.41%

                                                          │ main-bench.txt │            pr-bench.txt            │
                                                          │      B/op      │     B/op      vs base              │
ReclaimLargeJobs_10Node-4                                     17.20Mi ± 1%   17.22Mi ± 1%       ~ (p=0.485 n=6)
ReclaimLargeJobs_50Node-4                                     91.95Mi ± 0%   91.92Mi ± 0%       ~ (p=0.937 n=6)
ReclaimLargeJobs_100Node-4                                    204.2Mi ± 0%   204.2Mi ± 0%  +0.03% (p=0.026 n=6)
ReclaimLargeJobs_200Node-4                                    486.2Mi ± 0%   486.2Mi ± 0%       ~ (p=0.937 n=6)
ReclaimLargeJobs_500Node-4                                    1.698Gi ± 0%   1.698Gi ± 0%       ~ (p=1.000 n=6)
ReclaimLargeJobs_1000Node-4                                   5.141Gi ± 0%   5.141Gi ± 0%       ~ (p=0.589 n=6)
ReclaimManySingleGPUJobsFullCycle_10Node-4                    14.80Mi ± 0%   14.81Mi ± 0%       ~ (p=0.485 n=6)
ReclaimManySingleGPUJobsFullCycle_50Node-4                    145.0Mi ± 0%   145.0Mi ± 0%       ~ (p=0.394 n=6)
ReclaimManySingleGPUJobsFullCycle_100Node-4                   470.6Mi ± 0%   470.7Mi ± 0%       ~ (p=0.699 n=6)
ReclaimManySingleGPUJobsFullCycle_200Node-4                   1.630Gi ± 0%   1.630Gi ± 0%       ~ (p=0.240 n=6)
ReclaimManySingleGPUJobsFullCycle_500Node-4                   10.34Gi ± 0%   10.34Gi ± 0%       ~ (p=0.310 n=6)
ReclaimManySingleGPUJobsFullCycleWithMinRuntime_500Node-4     10.35Gi ± 0%   10.34Gi ± 0%       ~ (p=0.180 n=6)
geomean                                                       504.5Mi        504.6Mi       +0.01%

                                                          │ main-bench.txt │           pr-bench.txt            │
                                                          │   allocs/op    │  allocs/op   vs base              │
ReclaimLargeJobs_10Node-4                                      242.0k ± 0%   242.0k ± 0%       ~ (p=0.292 n=6)
ReclaimLargeJobs_50Node-4                                      1.482M ± 0%   1.482M ± 0%       ~ (p=0.699 n=6)
ReclaimLargeJobs_100Node-4                                     3.741M ± 0%   3.741M ± 0%       ~ (p=0.699 n=6)
ReclaimLargeJobs_200Node-4                                     10.52M ± 0%   10.52M ± 0%       ~ (p=0.818 n=6)
ReclaimLargeJobs_500Node-4                                     45.58M ± 0%   45.58M ± 0%       ~ (p=0.699 n=6)
ReclaimLargeJobs_1000Node-4                                    159.5M ± 0%   159.5M ± 0%       ~ (p=0.937 n=6)
ReclaimManySingleGPUJobsFullCycle_10Node-4                     279.9k ± 0%   279.9k ± 0%       ~ (p=0.506 n=6)
ReclaimManySingleGPUJobsFullCycle_50Node-4                     3.741M ± 0%   3.742M ± 0%       ~ (p=0.093 n=6)
ReclaimManySingleGPUJobsFullCycle_100Node-4                    13.33M ± 0%   13.33M ± 0%       ~ (p=0.818 n=6)
ReclaimManySingleGPUJobsFullCycle_200Node-4                    50.07M ± 0%   50.07M ± 0%       ~ (p=0.180 n=6)
ReclaimManySingleGPUJobsFullCycle_500Node-4                    300.6M ± 0%   300.6M ± 0%       ~ (p=0.180 n=6)
ReclaimManySingleGPUJobsFullCycleWithMinRuntime_500Node-4      300.6M ± 0%   300.6M ± 0%       ~ (p=0.589 n=6)
geomean                                                        11.69M        11.69M       -0.00%

                                                          │ main-bench.txt │              pr-bench.txt              │
                                                          │ full_cycles/op │ full_cycles/op  vs base                │
ReclaimManySingleGPUJobsFullCycle_10Node-4                      1.000 ± 0%       1.000 ± 0%       ~ (p=1.000 n=6) ¹
ReclaimManySingleGPUJobsFullCycle_50Node-4                      1.000 ± 0%       1.000 ± 0%       ~ (p=1.000 n=6) ¹
ReclaimManySingleGPUJobsFullCycle_100Node-4                     1.000 ± 0%       1.000 ± 0%       ~ (p=1.000 n=6) ¹
ReclaimManySingleGPUJobsFullCycle_200Node-4                     1.000 ± 0%       1.000 ± 0%       ~ (p=1.000 n=6) ¹
ReclaimManySingleGPUJobsFullCycle_500Node-4                     1.000 ± 0%       1.000 ± 0%       ~ (p=1.000 n=6) ¹
ReclaimManySingleGPUJobsFullCycleWithMinRuntime_500Node-4       1.000 ± 0%       1.000 ± 0%       ~ (p=1.000 n=6) ¹
geomean                                                         1.000            1.000       +0.00%
¹ all samples are equal

                                            │          main-bench.txt           │                     pr-bench.txt                     │
                                            │ fit_error_tasks_after_allocate/op │ fit_error_tasks_after_allocate/op  vs base           │
ReclaimManySingleGPUJobsFullCycle_500Node-4                         4.000k ± 0%                         4.000k ± 0%  ~ (p=1.000 n=6) ¹
¹ all samples are equal

                                            │          main-bench.txt           │                    pr-bench.txt                    │
                                            │ heap_live_after_allocate_bytes/op │ heap_live_after_allocate_bytes/op  vs base         │
ReclaimManySingleGPUJobsFullCycle_500Node-4                        41.55M ± 76%                        41.55M ± 76%  ~ (p=0.699 n=6)

                                            │         main-bench.txt         │                  pr-bench.txt                   │
                                            │ heap_live_after_cycle_bytes/op │ heap_live_after_cycle_bytes/op  vs base         │
ReclaimManySingleGPUJobsFullCycle_500Node-4                     56.14M ± 56%                     56.18M ± 56%  ~ (p=0.240 n=6)

pkg: github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/actions/preempt
                                  │ main-bench.txt │           pr-bench.txt            │
                                  │     sec/op     │   sec/op     vs base              │
OrderedVictimsQueueConstruction-4      733.8µ ± 1%   777.8µ ± 0%  +6.01% (p=0.002 n=6)

                                  │ main-bench.txt │          pr-bench.txt           │
                                  │      B/op      │     B/op      vs base           │
OrderedVictimsQueueConstruction-4     114.9Ki ± 0%   114.9Ki ± 0%  ~ (p=1.000 n=6) ¹
¹ all samples are equal

                                  │ main-bench.txt │          pr-bench.txt          │
                                  │   allocs/op    │  allocs/op   vs base           │
OrderedVictimsQueueConstruction-4      4.033k ± 0%   4.033k ± 0%  ~ (p=1.000 n=6) ¹
¹ all samples are equal

pkg: github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/actions/reclaim
                                                         │ main-bench.txt │           pr-bench.txt            │
                                                         │     sec/op     │   sec/op     vs base              │
ReclaimUnschedulableDistributedJob_10Node-4                   151.0m ± 1%   150.4m ± 1%       ~ (p=0.699 n=6)
ReclaimUnschedulableDistributedJob_50Node-4                    3.768 ± 2%    3.805 ± 3%       ~ (p=0.093 n=6)
ReclaimUnschedulableDistributedJob_100Node-4                   17.70 ± 1%    17.75 ± 3%       ~ (p=0.589 n=6)
ReclaimUnschedulableDistributedJob_AntiAffinity100Node-4       16.25 ± 1%    16.42 ± 1%       ~ (p=0.180 n=6)
ReclaimWithMissingPVCJobs-4                                   2.688m ± 6%   2.629m ± 3%       ~ (p=0.180 n=6)
geomean                                                       848.6m        848.1m       -0.06%

                                                         │ main-bench.txt │            pr-bench.txt            │
                                                         │      B/op      │     B/op      vs base              │
ReclaimUnschedulableDistributedJob_10Node-4                  20.93Mi ± 3%   20.91Mi ± 3%       ~ (p=0.699 n=6)
ReclaimUnschedulableDistributedJob_50Node-4                  1.154Gi ± 0%   1.154Gi ± 0%       ~ (p=0.589 n=6)
ReclaimUnschedulableDistributedJob_100Node-4                 5.560Gi ± 0%   5.559Gi ± 0%       ~ (p=0.180 n=6)
ReclaimUnschedulableDistributedJob_AntiAffinity100Node-4     5.158Gi ± 0%   5.158Gi ± 0%       ~ (p=0.485 n=6)
ReclaimWithMissingPVCJobs-4                                  9.055Ki ± 2%   9.055Ki ± 2%       ~ (p=0.773 n=6)
geomean                                                      91.97Mi        91.95Mi       -0.02%

                                                         │ main-bench.txt │           pr-bench.txt            │
                                                         │   allocs/op    │  allocs/op   vs base              │
ReclaimUnschedulableDistributedJob_10Node-4                   306.1k ± 3%   306.1k ± 3%       ~ (p=0.853 n=6)
ReclaimUnschedulableDistributedJob_50Node-4                   27.77M ± 0%   27.77M ± 0%       ~ (p=1.000 n=6)
ReclaimUnschedulableDistributedJob_100Node-4                  169.0M ± 0%   169.0M ± 0%       ~ (p=0.180 n=6)
ReclaimUnschedulableDistributedJob_AntiAffinity100Node-4      146.8M ± 0%   146.8M ± 0%       ~ (p=0.699 n=6)
ReclaimWithMissingPVCJobs-4                                    170.0 ± 1%    170.0 ± 1%       ~ (p=0.636 n=6)
geomean                                                       2.046M        2.046M       +0.00%

                                                         │ main-bench.txt │             pr-bench.txt             │
                                                         │  duplicate/op  │ duplicate/op  vs base                │
ReclaimUnschedulableDistributedJob_10Node-4                  0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=6) ¹
ReclaimUnschedulableDistributedJob_50Node-4                  366.0 ± 0%       366.0 ± 0%       ~ (p=1.000 n=6) ¹
ReclaimUnschedulableDistributedJob_100Node-4                1.020k ± 0%      1.020k ± 0%       ~ (p=1.000 n=6) ¹
ReclaimUnschedulableDistributedJob_AntiAffinity100Node-4    1.020k ± 0%      1.020k ± 0%       ~ (p=1.000 n=6) ¹
geomean                                                                 ²                 +0.00%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                                         │ main-bench.txt │             pr-bench.txt             │
                                                         │  simulated/op  │ simulated/op  vs base                │
ReclaimUnschedulableDistributedJob_10Node-4                    18.00 ± 0%     18.00 ± 0%       ~ (p=1.000 n=6) ¹
ReclaimUnschedulableDistributedJob_50Node-4                    178.0 ± 0%     178.0 ± 0%       ~ (p=1.000 n=6) ¹
ReclaimUnschedulableDistributedJob_100Node-4                   378.0 ± 0%     378.0 ± 0%       ~ (p=1.000 n=6) ¹
ReclaimUnschedulableDistributedJob_AntiAffinity100Node-4       378.0 ± 0%     378.0 ± 0%       ~ (p=1.000 n=6) ¹
geomean                                                        146.3          146.3       +0.00%
¹ all samples are equal

Legend

  • 📉 Negative delta = Performance improvement (faster)
  • 📈 Positive delta = Performance regression (slower)
  • p-value < 0.05 indicates statistically significant change
Raw benchmark data

PR branch:

goos: linux
goarch: amd64
pkg: github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/actions
cpu: AMD EPYC 7763 64-Core Processor                
BenchmarkAllocateAction_SmallCluster-4         	       9	 116324939 ns/op	 2214658 B/op	   31501 allocs/op
BenchmarkAllocateAction_SmallCluster-4         	      10	 108506808 ns/op	 2186884 B/op	   31491 allocs/op
BenchmarkAllocateAction_SmallCluster-4         	      10	 108523584 ns/op	 2183494 B/op	   31493 allocs/op
BenchmarkAllocateAction_SmallCluster-4         	      10	 108580027 ns/op	 2172244 B/op	   31492 allocs/op
BenchmarkAllocateAction_SmallCluster-4         	      10	 108384948 ns/op	 2188600 B/op	   31497 allocs/op
BenchmarkAllocateAction_SmallCluster-4         	      10	 108607870 ns/op	 2185657 B/op	   31491 allocs/op
BenchmarkAllocateAction_MediumCluster-4        	       8	 135461252 ns/op	10383473 B/op	  245778 allocs/op
BenchmarkAllocateAction_MediumCluster-4        	       8	 134373533 ns/op	10386107 B/op	  245794 allocs/op
BenchmarkAllocateAction_MediumCluster-4        	       8	 135862991 ns/op	10383462 B/op	  245785 allocs/op
BenchmarkAllocateAction_MediumCluster-4        	       8	 136709260 ns/op	10384886 B/op	  245803 allocs/op
BenchmarkAllocateAction_MediumCluster-4        	       8	 136220714 ns/op	10384357 B/op	  245792 allocs/op
BenchmarkAllocateAction_MediumCluster-4        	       8	 136190456 ns/op	10382951 B/op	  245745 allocs/op
BenchmarkAllocateAction_LargeCluster-4         	       6	 201933108 ns/op	32776625 B/op	 1007170 allocs/op
BenchmarkAllocateAction_LargeCluster-4         	       6	 199603673 ns/op	32778626 B/op	 1007202 allocs/op
BenchmarkAllocateAction_LargeCluster-4         	       6	 197562295 ns/op	32781860 B/op	 1007208 allocs/op
BenchmarkAllocateAction_LargeCluster-4         	       6	 198445267 ns/op	32776757 B/op	 1007105 allocs/op
BenchmarkAllocateAction_LargeCluster-4         	       6	 194062142 ns/op	32768818 B/op	 1007169 allocs/op
BenchmarkAllocateAction_LargeCluster-4         	       6	 199480210 ns/op	32800136 B/op	 1007202 allocs/op
BenchmarkReclaimAction_SmallCluster-4          	      10	 103220959 ns/op	  973549 B/op	    8934 allocs/op
BenchmarkReclaimAction_SmallCluster-4          	      10	 103425047 ns/op	  971133 B/op	    8936 allocs/op
BenchmarkReclaimAction_SmallCluster-4          	      10	 103982582 ns/op	  974898 B/op	    8938 allocs/op
BenchmarkReclaimAction_SmallCluster-4          	      10	 103856422 ns/op	  974679 B/op	    8937 allocs/op
BenchmarkReclaimAction_SmallCluster-4          	      10	 103703284 ns/op	  978520 B/op	    8937 allocs/op
BenchmarkReclaimAction_SmallCluster-4          	      10	 103720036 ns/op	  983807 B/op	    8939 allocs/op
BenchmarkReclaimAction_MediumCluster-4         	      10	 106884439 ns/op	 3253121 B/op	   28119 allocs/op
BenchmarkReclaimAction_MediumCluster-4         	      10	 106689575 ns/op	 3257548 B/op	   28120 allocs/op
BenchmarkReclaimAction_MediumCluster-4         	      10	 106590372 ns/op	 3257301 B/op	   28119 allocs/op
BenchmarkReclaimAction_MediumCluster-4         	      10	 106791767 ns/op	 3249234 B/op	   28117 allocs/op
BenchmarkReclaimAction_MediumCluster-4         	      10	 106592548 ns/op	 3253052 B/op	   28118 allocs/op
BenchmarkReclaimAction_MediumCluster-4         	      10	 106658052 ns/op	 3254018 B/op	   28119 allocs/op
BenchmarkPreemptAction_SmallCluster-4          	      10	 104415208 ns/op	 1407978 B/op	   15267 allocs/op
BenchmarkPreemptAction_SmallCluster-4          	      10	 104728699 ns/op	 1412245 B/op	   15270 allocs/op
BenchmarkPreemptAction_SmallCluster-4          	      10	 104561093 ns/op	 1407874 B/op	   15266 allocs/op
BenchmarkPreemptAction_SmallCluster-4          	      10	 104859068 ns/op	 1412088 B/op	   15271 allocs/op
BenchmarkPreemptAction_SmallCluster-4          	      10	 104566013 ns/op	 1418354 B/op	   15268 allocs/op
BenchmarkPreemptAction_SmallCluster-4          	      10	 104816124 ns/op	 1411962 B/op	   15270 allocs/op
BenchmarkPreemptAction_MediumCluster-4         	       9	 116953316 ns/op	 6224361 B/op	   55293 allocs/op
BenchmarkPreemptAction_MediumCluster-4         	       9	 115594613 ns/op	 6228274 B/op	   55292 allocs/op
BenchmarkPreemptAction_MediumCluster-4         	       9	 114928219 ns/op	 6224338 B/op	   55292 allocs/op
BenchmarkPreemptAction_MediumCluster-4         	       9	 117064951 ns/op	 6220079 B/op	   55291 allocs/op
BenchmarkPreemptAction_MediumCluster-4         	       9	 117334859 ns/op	 6220029 B/op	   55291 allocs/op
BenchmarkPreemptAction_MediumCluster-4         	       9	 117171816 ns/op	 6224422 B/op	   55293 allocs/op
BenchmarkConsolidationAction_SmallCluster-4    	       9	 123425015 ns/op	 8604363 B/op	  109675 allocs/op
BenchmarkConsolidationAction_SmallCluster-4    	       9	 123572313 ns/op	 8600243 B/op	  109648 allocs/op
BenchmarkConsolidationAction_SmallCluster-4    	       9	 123243225 ns/op	 8597638 B/op	  109623 allocs/op
BenchmarkConsolidationAction_SmallCluster-4    	       9	 122486515 ns/op	 8607360 B/op	  109635 allocs/op

Main branch:

goos: linux
goarch: amd64
pkg: github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/actions
cpu: AMD EPYC 7763 64-Core Processor                
BenchmarkAllocateAction_SmallCluster-4         	      10	 108669670 ns/op	 2188531 B/op	   31500 allocs/op
BenchmarkAllocateAction_SmallCluster-4         	      10	 108237163 ns/op	 2183623 B/op	   31491 allocs/op
BenchmarkAllocateAction_SmallCluster-4         	      10	 108785947 ns/op	 2190756 B/op	   31488 allocs/op
BenchmarkAllocateAction_SmallCluster-4         	      10	 108583848 ns/op	 2171686 B/op	   31494 allocs/op
BenchmarkAllocateAction_SmallCluster-4         	      10	 108600953 ns/op	 2171820 B/op	   31489 allocs/op
BenchmarkAllocateAction_SmallCluster-4         	      10	 108315415 ns/op	 2173366 B/op	   31489 allocs/op
BenchmarkAllocateAction_MediumCluster-4        	       8	 136326751 ns/op	10397729 B/op	  245814 allocs/op
BenchmarkAllocateAction_MediumCluster-4        	       8	 135823228 ns/op	10384331 B/op	  245773 allocs/op
BenchmarkAllocateAction_MediumCluster-4        	       8	 137136064 ns/op	10386055 B/op	  245776 allocs/op
BenchmarkAllocateAction_MediumCluster-4        	       8	 137715400 ns/op	10383356 B/op	  245810 allocs/op
BenchmarkAllocateAction_MediumCluster-4        	       8	 136321997 ns/op	10384945 B/op	  245803 allocs/op
BenchmarkAllocateAction_MediumCluster-4        	       8	 137066670 ns/op	10385045 B/op	  245775 allocs/op
BenchmarkAllocateAction_LargeCluster-4         	       6	 203721361 ns/op	32776370 B/op	 1007158 allocs/op
BenchmarkAllocateAction_LargeCluster-4         	       5	 203421077 ns/op	32777822 B/op	 1007154 allocs/op
BenchmarkAllocateAction_LargeCluster-4         	       5	 200655099 ns/op	32773401 B/op	 1007174 allocs/op
BenchmarkAllocateAction_LargeCluster-4         	       6	 197425823 ns/op	32787425 B/op	 1007209 allocs/op
BenchmarkAllocateAction_LargeCluster-4         	       6	 198734170 ns/op	32809552 B/op	 1007167 allocs/op
BenchmarkAllocateAction_LargeCluster-4         	       6	 207571872 ns/op	32791881 B/op	 1007212 allocs/op
BenchmarkReclaimAction_SmallCluster-4          	      10	 103951008 ns/op	  977807 B/op	    8937 allocs/op
BenchmarkReclaimAction_SmallCluster-4          	      10	 103620552 ns/op	  978292 B/op	    8936 allocs/op
BenchmarkReclaimAction_SmallCluster-4          	      10	 103729388 ns/op	  978248 B/op	    8937 allocs/op
BenchmarkReclaimAction_SmallCluster-4          	      10	 103849661 ns/op	  978346 B/op	    8937 allocs/op
BenchmarkReclaimAction_SmallCluster-4          	      10	 103819949 ns/op	  978488 B/op	    8937 allocs/op
BenchmarkReclaimAction_SmallCluster-4          	      10	 103671573 ns/op	  978479 B/op	    8938 allocs/op
BenchmarkReclaimAction_MediumCluster-4         	      10	 107359093 ns/op	 3261820 B/op	   28120 allocs/op
BenchmarkReclaimAction_MediumCluster-4         	      10	 106754478 ns/op	 3257537 B/op	   28120 allocs/op
BenchmarkReclaimAction_MediumCluster-4         	      10	 107638055 ns/op	 3257100 B/op	   28120 allocs/op
BenchmarkReclaimAction_MediumCluster-4         	      10	 107566671 ns/op	 3257036 B/op	   28120 allocs/op
BenchmarkReclaimAction_MediumCluster-4         	      10	 107298678 ns/op	 3257126 B/op	   28121 allocs/op
BenchmarkReclaimAction_MediumCluster-4         	      10	 106778299 ns/op	 3249769 B/op	   28118 allocs/op
BenchmarkPreemptAction_SmallCluster-4          	      10	 104813122 ns/op	 1412845 B/op	   15269 allocs/op
BenchmarkPreemptAction_SmallCluster-4          	      10	 104908511 ns/op	 1411719 B/op	   15269 allocs/op
BenchmarkPreemptAction_SmallCluster-4          	      10	 104810459 ns/op	 1404178 B/op	   15267 allocs/op
BenchmarkPreemptAction_SmallCluster-4          	      10	 104905666 ns/op	 1411644 B/op	   15268 allocs/op
BenchmarkPreemptAction_SmallCluster-4          	      10	 104797650 ns/op	 1411887 B/op	   15270 allocs/op
BenchmarkPreemptAction_SmallCluster-4          	      10	 104791060 ns/op	 1410516 B/op	   15266 allocs/op
BenchmarkPreemptAction_MediumCluster-4         	       9	 116780703 ns/op	 6219618 B/op	   55290 allocs/op
BenchmarkPreemptAction_MediumCluster-4         	       9	 115285345 ns/op	 6224304 B/op	   55293 allocs/op
BenchmarkPreemptAction_MediumCluster-4         	       9	 117470215 ns/op	 6224231 B/op	   55293 allocs/op
BenchmarkPreemptAction_MediumCluster-4         	       9	 117308856 ns/op	 6215574 B/op	   55290 allocs/op
BenchmarkPreemptAction_MediumCluster-4         	       9	 115880747 ns/op	 6224214 B/op	   55293 allocs/op
BenchmarkPreemptAction_MediumCluster-4         	       9	 117734261 ns/op	 6224088 B/op	   55292 allocs/op
BenchmarkConsolidationAction_SmallCluster-4    	       9	 123527947 ns/op	 8613677 B/op	  109675 allocs/op
BenchmarkConsolidationAction_SmallCluster-4    	       9	 124107608 ns/op	 8614743 B/op	  109665 allocs/op
BenchmarkConsolidationAction_SmallCluster-4    	       9	 123489360 ns/op	 8600786 B/op	  109657 allocs/op
BenchmarkConsolidationAction_SmallCluster-4    	       9	 122970494 ns/op	 8605168 B/op	  109679 allocs/op

…hmark regression

Signed-off-by: CoolingCube <CoolingCubeInfo@proton.me>
@CoolingCube

Copy link
Copy Markdown
Contributor Author

The benchmark bot's regression above was real, traced it to the reclaim action rebuilding its entire victims queue once per candidate reclaimer job (pre-existing behavior), which made GetAliveTasksRequestedGPUs()'s per-call cost newly visible at scale. Cached it the same way activeAllocatedCount already is on PodGroupInfo, should resolve once the fresh benchmark run goes through. Let me know if you'd rather see something different.

Signed-off-by: CoolingCube <CoolingCubeInfo@proton.me>
@github-actions

github-actions Bot commented Jul 31, 2026

Copy link
Copy Markdown

Total coverage: 54.6% -> 54.6% (delta 0.00%)

Merging this branch changes the coverage (1 decrease, 2 increase)

Impacted Packages Coverage Δ 🤖
github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/actions/utils 57.66% (ø)
github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/api/podgroup_info 70.57% (-0.27%) 👎
github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/framework 51.03% (+0.93%) 👍
github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/plugins 0.00% (ø)
github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/plugins/gpujoborder 95.65% (+95.65%) 🌟

Coverage by file

Changed files (no unit tests)

Changed File Coverage Δ Total Covered Missed 🤖
github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/actions/utils/job_order_by_queue.go 85.48% (ø) 124 106 18
github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/api/podgroup_info/job_info.go 60.85% (-0.32%) 258 (+3) 157 (+1) 101 (+2) 👎
github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/framework/session.go 38.18% (+0.23%) 275 (+1) 105 (+1) 170 👍
github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/framework/session_plugins.go 43.48% (+5.19%) 184 (+9) 80 (+13) 104 (-4) 👍
github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/plugins/factory.go 0.00% (ø) 25 (+1) 0 25 (+1)
github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/plugins/gpujoborder/gpujoborder.go 95.65% (+95.65%) 23 (+23) 22 (+22) 1 (+1) 🌟

Please note that the "Total", "Covered", and "Missed" counts above refer to code statements instead of lines of code. The value in brackets refers to the test coverage of that file in the old version of the code.

Changed unit test files

  • github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/framework/session_plugins_test.go
  • github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/plugins/gpujoborder/gpujoborder_test.go

@CoolingCube

Copy link
Copy Markdown
Contributor Author

Just checking in, this has been green for a while now (perf fix, license/formatting fix, and the naming/constants changes from your review are all in). No rush at all, just didn't want it to slip off the radar. Let me know if there's anything else you'd like changed.

enoodle
enoodle previously approved these changes Aug 6, 2026

@enoodle enoodle left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @CoolingCube ! I wanted to look for ways to allow integrating such plugins more easily without requiring review and merge into this repo, but I think we should merge it for now anyway.

@gshaibi

gshaibi commented Aug 6, 2026

Copy link
Copy Markdown
Member

Hi @CoolingCube, thanks for contributing.
The JobOrder plugins apply not only to victims, but also to pending jobs order - does it match with your intention? what does larger/smaller job mean when choosing a job to allocate?

@CoolingCube

Copy link
Copy Markdown
Contributor Author

Good question @gshaibi and worth being precise: this isn't hypothetical. job_order_by_queue.go uses the same ssn.JobOrderFn for both victim selection and pending-job ordering, just inverted for the victim case, so gpujoborder is already active on the ordering path too, not something that would apply if extended.
Honestly, I don't think 'larger/smaller' obviously means the same thing for choosing which job to allocate as it does for choosing which job to evict, for eviction it's about disruption cost, but for allocation it's not clear preferring one size over another is right at all. I don't have real evidence either way for the ordering case specifically. Happy to think through what the right behavior there should be, or whether ordering should be scoped out of this plugin's tiebreak entirely, since it's a genuinely separate question from eviction.

@gshaibi

gshaibi commented Aug 6, 2026

Copy link
Copy Markdown
Member

Good question @gshaibi and worth being precise: this isn't hypothetical. job_order_by_queue.go uses the same ssn.JobOrderFn for both victim selection and pending-job ordering, just inverted for the victim case, so gpujoborder is already active on the ordering path too, not something that would apply if extended. Honestly, I don't think 'larger/smaller' obviously means the same thing for choosing which job to allocate as it does for choosing which job to evict, for eviction it's about disruption cost, but for allocation it's not clear preferring one size over another is right at all. I don't have real evidence either way for the ordering case specifically. Happy to think through what the right behavior there should be, or whether ordering should be scoped out of this plugin's tiebreak entirely, since it's a genuinely separate question from eviction.

Thanks, I agree that allocation order is a separate question. Since this change is intended to control victim selection, it shouldn’t affect the order of pending jobs.

Also, because the victim queue reverses JobOrderFn, prefer-larger currently schedules larger jobs first but selects smaller jobs as victims.

Would it be possible to scope this behavior to victim selection only and add a test confirming that pending-job ordering remains unchanged?

@CoolingCube

Copy link
Copy Markdown
Contributor Author

Good question @gshaibi and worth being precise: this isn't hypothetical. job_order_by_queue.go uses the same ssn.JobOrderFn for both victim selection and pending-job ordering, just inverted for the victim case, so gpujoborder is already active on the ordering path too, not something that would apply if extended. Honestly, I don't think 'larger/smaller' obviously means the same thing for choosing which job to allocate as it does for choosing which job to evict, for eviction it's about disruption cost, but for allocation it's not clear preferring one size over another is right at all. I don't have real evidence either way for the ordering case specifically. Happy to think through what the right behavior there should be, or whether ordering should be scoped out of this plugin's tiebreak entirely, since it's a genuinely separate question from eviction.

Thanks, I agree that allocation order is a separate question. Since this change is intended to control victim selection, it shouldn’t affect the order of pending jobs.

Also, because the victim queue reverses JobOrderFn, prefer-larger currently schedules larger jobs first but selects smaller jobs as victims.

Would it be possible to scope this behavior to victim selection only and add a test confirming that pending-job ordering remains unchanged?

Ran it against the merged code directly and it matches exactly what you flagged: prefer-larger evicts the smaller job, because the victim queue's inversion flips the same sign that makes larger jobs allocate first. Good catch, and it's exactly why scoping this to victim-selection only isn't just cleanup, a single shared comparator genuinely can't satisfy both paths correctly at once.
I don't see an existing way to register a comparator that only applies to the victim queue in the current framework, JobOrderFn's signature has no way to know which queue it's being called from, so this would likely need a real extension point rather than a small patch, which sounds related to what enoodle mentioned wanting to explore anyway.
Given this is already approved, wanted to flag it before it merges rather than after. Happy to take a pass at either a scoped fix or a minimal sign correction in the meantime whichever's more useful.

…ctimOrderFn extension point

Fixes a sign-inversion bug where prefer-larger evicted the smaller job
(the victim queue's !JobOrderFn inversion flipped the same sign used
for pending-job ordering). Adds Session.VictimOrderFn/AddVictimOrderFn
as a dedicated, non-inverted composition path for victim-specific
comparators, falling back to the existing !JobOrderFn behavior when
none are registered, so no other plugin's behavior changes. gpujoborder
now registers exclusively via AddVictimOrderFn and no longer affects
pending-job allocation ordering at all.

Addresses @gshaibi's review comment on kai-scheduler#1995.

Signed-off-by: CoolingCube <CoolingCubeInfo@proton.me>
@CoolingCube

Copy link
Copy Markdown
Contributor Author

Pushed the fix added a dedicated VictimOrderFn/AddVictimOrderFn extension point so victim-specific comparators no longer share (or invert) the same sign used for pending-job ordering. gpujoborder now registers only via the new path. Added a test confirming pending-job ordering is byte-identical with or without the plugin registered. Full framework/actions suite passes

@gshaibi gshaibi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, left two more comments.

Comment thread pkg/scheduler/framework/session_plugins.go
Comment thread pkg/scheduler/plugins/gpujoborder/gpujoborder.go Outdated
…erFns; rename modes for clarity

Addresses @gshaibi's two review comments:

1. VictimOrderFn now checks the JobOrderFns chain first (priority.go,
   elastic.go, etc.) and only falls through to VictimOrderFns as a
   tiebreak when no registered JobOrderFn has an opinion. Previously,
   VictimOrderFns were checked unconditionally first, letting a raw
   resource-size comparator outrank elastic's at-min/above-min
   protection. New test confirms elastic correctly outranks gpujoborder
   now.

2. Renamed prefer-larger/prefer-smaller to evict-larger-first/
   evict-smaller-first to remove ambiguity about whether the mode means
   'prefer to keep' or 'prefer to evict' the larger job. Added package
   and constant documentation.

Signed-off-by: CoolingCube <CoolingCubeInfo@proton.me>
…helper

Each task in a multi-task subgroup was getting an identical UID,
causing the second task to silently overwrite the first in the pod
map used by GetAliveTasksRequestedGPUs(). Didn't affect the test's
pass/fail correctness (elastic's own task-count tracking uses a
separate counter, unaffected by the collision, and short-circuits
before gpujoborder's comparator is ever consulted) but did produce a
misleading debug log value. Fixed by giving each task a unique UID.

Signed-off-by: CoolingCube <CoolingCubeInfo@proton.me>
@CoolingCube

Copy link
Copy Markdown
Contributor Author

Pushed a fix for both

For the composition order: you're right, VictimOrderFn was checking victim-specific comparators before the existing JobOrderFns chain, so a raw GPU-size comparison could outrank elastic's at-min/above-min protection. Fixed exactly as you outlined, the raw JobOrderFns are checked first (inverted), VictimOrderFns only apply as a tiebreak, and the CreationTimestamp/UID fallback is now shared via jobOrderCreationFallback so both paths stay consistent. Added a test with both elastic and gpujoborder registered together confirming elastic's protection wins (with a follow-up commit fixing a duplicate-UID bug in the test helper itself, so the confirmed GPU numbers are accurate too).

For the naming: agreed, renamed to evict-larger-first/evict-smaller-first and added doc comments on the package and both constants."

Comment thread pkg/scheduler/framework/session_plugins.go Outdated
Signed-off-by: CoolingCube <CoolingCubeInfo@proton.me>

@gshaibi gshaibi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. One thing I am missing is documentation, especially regarding the new extension point.
@davidLif you had some concerns - feel free to point them out.

@davidLif davidLif left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the addition of VictimOrderFn, this PR needs to add some integration tests making sure that plugins with a JobOrderFn still effect the victims order, preserving exisitng logic.

Comment thread pkg/scheduler/api/podgroup_info/job_info.go
Comment thread pkg/scheduler/framework/session_plugins.go
… convention

Signed-off-by: CoolingCube <CoolingCubeInfo@proton.me>
Signed-off-by: CoolingCube <CoolingCubeInfo@proton.me>

@gshaibi gshaibi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@CoolingCube

Copy link
Copy Markdown
Contributor Author

@davidLif, I went ahead and resolved the two threads above since the fixes/tests covered them. tell me if you want another look at anything ?

@davidLif
davidLif added this pull request to the merge queue Aug 23, 2026
Merged via the queue into kai-scheduler:main with commit 28882c5 Aug 23, 2026
26 of 28 checks passed
@KaiPilotBot

Copy link
Copy Markdown
Collaborator

📝 Changelog fragment recorded

Thanks! This PR added the changelog fragment(s) below. Pending fragments are folded into CHANGELOG.md at release time, so it was intentionally not modified by this PR — your entry will appear in the next release:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

preempt: JobOrderFn tiebreak has no resource-awareness, falls back to creation-time order

5 participants